1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 import java.lang.ProcessBuilder.Redirect;
36 import static java.lang.ProcessBuilder.Redirect.*;
37
38 import java.io.*;
39 import java.util.*;
40 import java.util.concurrent.CountDownLatch;
41 import java.security.*;
42 import java.util.regex.Pattern;
43 import static java.lang.System.getenv;
44 import static java.lang.System.out;
45 import static java.lang.Boolean.TRUE;
46 import static java.util.AbstractMap.SimpleImmutableEntry;
47
48 public class Basic {
49
50
51 static final String systemRoot = System.getenv("SystemRoot");
52
53 private static String commandOutput(Reader r) throws Throwable {
54 StringBuilder sb = new StringBuilder();
55 int c;
56 while ((c = r.read()) > 0)
57 if (c != '\r')
58 sb.append((char) c);
59 return sb.toString();
60 }
61
62 private static String commandOutput(Process p) throws Throwable {
63 check(p.getInputStream() == p.getInputStream());
64 check(p.getOutputStream() == p.getOutputStream());
65 check(p.getErrorStream() == p.getErrorStream());
66 Reader r = new InputStreamReader(p.getInputStream(),"UTF-8");
67 String output = commandOutput(r);
68 equal(p.waitFor(), 0);
69 equal(p.exitValue(), 0);
70 return output;
71 }
72
73 private static String commandOutput(ProcessBuilder pb) {
74 try {
75 return commandOutput(pb.start());
76 } catch (Throwable t) {
77 String commandline = "";
78 for (String arg : pb.command())
79 commandline += " " + arg;
80 System.out.println("Exception trying to run process: " + commandline);
81 unexpected(t);
82 return "";
83 }
84 }
85
86 private static String commandOutput(String...command) {
87 try {
88 return commandOutput(Runtime.getRuntime().exec(command));
89 } catch (Throwable t) {
90 String commandline = "";
91 for (String arg : command)
92 commandline += " " + arg;
93 System.out.println("Exception trying to run process: " + commandline);
94 unexpected(t);
95 return "";
96 }
97 }
98
99 private static void checkCommandOutput(ProcessBuilder pb,
100 String expected,
101 String failureMsg) {
102 String got = commandOutput(pb);
103 check(got.equals(expected),
104 failureMsg + "\n" +
105 "Expected: \"" + expected + "\"\n" +
106 "Got: \"" + got + "\"");
107 }
108
109 private static String absolutifyPath(String path) {
110 StringBuilder sb = new StringBuilder();
111 for (String file : path.split(File.pathSeparator)) {
112 if (sb.length() != 0)
113 sb.append(File.pathSeparator);
114 sb.append(new File(file).getAbsolutePath());
115 }
116 return sb.toString();
117 }
118
119
120
121 private static class WindowsComparator
122 implements Comparator<String> {
123 public int compare(String x, String y) {
124 return x.toUpperCase(Locale.US)
125 .compareTo(y.toUpperCase(Locale.US));
126 }
127 }
128
129 private static String sortedLines(String lines) {
130 String[] arr = lines.split("\n");
131 List<String> ls = new ArrayList<String>();
132 for (String s : arr)
133 ls.add(s);
134 Collections.sort(ls, new WindowsComparator());
135 StringBuilder sb = new StringBuilder();
136 for (String s : ls)
137 sb.append(s + "\n");
138 return sb.toString();
139 }
140
141 private static void compareLinesIgnoreCase(String lines1, String lines2) {
142 if (! (sortedLines(lines1).equalsIgnoreCase(sortedLines(lines2)))) {
143 String dashes =
144 "-----------------------------------------------------";
145 out.println(dashes);
146 out.print(sortedLines(lines1));
147 out.println(dashes);
148 out.print(sortedLines(lines2));
149 out.println(dashes);
150 out.println("sizes: " + sortedLines(lines1).length() +
151 " " + sortedLines(lines2).length());
152
153 fail("Sorted string contents differ");
154 }
155 }
156
157 private static final Runtime runtime = Runtime.getRuntime();
158
159 private static final String[] winEnvCommand = {"cmd.exe", "/c", "set"};
160
161 private static String winEnvFilter(String env) {
162 return env.replaceAll("\r", "")
163 .replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT)=.*\n","");
164 }
165
166 private static String unixEnvProg() {
167 return new File("/usr/bin/env").canExecute() ? "/usr/bin/env"
168 : "/bin/env";
169 }
170
171 private static String nativeEnv(String[] env) {
172 try {
173 if (Windows.is()) {
174 return winEnvFilter
175 (commandOutput(runtime.exec(winEnvCommand, env)));
176 } else {
177 return commandOutput(runtime.exec(unixEnvProg(), env));
178 }
179 } catch (Throwable t) { throw new Error(t); }
180 }
181
182 private static String nativeEnv(ProcessBuilder pb) {
183 try {
184 if (Windows.is()) {
185 pb.command(winEnvCommand);
186 return winEnvFilter(commandOutput(pb));
187 } else {
188 pb.command(new String[]{unixEnvProg()});
189 return commandOutput(pb);
190 }
191 } catch (Throwable t) { throw new Error(t); }
192 }
193
194 private static void checkSizes(Map<String,String> environ, int size) {
195 try {
196 equal(size, environ.size());
197 equal(size, environ.entrySet().size());
198 equal(size, environ.keySet().size());
199 equal(size, environ.values().size());
200
201 boolean isEmpty = (size == 0);
202 equal(isEmpty, environ.isEmpty());
203 equal(isEmpty, environ.entrySet().isEmpty());
204 equal(isEmpty, environ.keySet().isEmpty());
205 equal(isEmpty, environ.values().isEmpty());
206 } catch (Throwable t) { unexpected(t); }
207 }
208
209 private interface EnvironmentFrobber {
210 void doIt(Map<String,String> environ);
211 }
212
213 private static void testVariableDeleter(EnvironmentFrobber fooDeleter) {
214 try {
215 Map<String,String> environ = new ProcessBuilder().environment();
216 environ.put("Foo", "BAAR");
217 fooDeleter.doIt(environ);
218 equal(environ.get("Foo"), null);
219 equal(environ.remove("Foo"), null);
220 } catch (Throwable t) { unexpected(t); }
221 }
222
223 private static void testVariableAdder(EnvironmentFrobber fooAdder) {
224 try {
225 Map<String,String> environ = new ProcessBuilder().environment();
226 environ.remove("Foo");
227 fooAdder.doIt(environ);
228 equal(environ.get("Foo"), "Bahrein");
229 } catch (Throwable t) { unexpected(t); }
230 }
231
232 private static void testVariableModifier(EnvironmentFrobber fooModifier) {
233 try {
234 Map<String,String> environ = new ProcessBuilder().environment();
235 environ.put("Foo","OldValue");
236 fooModifier.doIt(environ);
237 equal(environ.get("Foo"), "NewValue");
238 } catch (Throwable t) { unexpected(t); }
239 }
240
241 private static void printUTF8(String s) throws IOException {
242 out.write(s.getBytes("UTF-8"));
243 }
244
245 private static String getenvAsString(Map<String,String> environment) {
246 StringBuilder sb = new StringBuilder();
247 for (Map.Entry<String,String> e : environment.entrySet())
248
249 if (! e.getKey().equals("NLSPATH") &&
250 ! e.getKey().equals("XFILESEARCHPATH") &&
251 ! e.getKey().equals("LD_LIBRARY_PATH"))
252 sb.append(e.getKey())
253 .append('=')
254 .append(e.getValue())
255 .append(',');
256 return sb.toString();
257 }
258
259 static void print4095(OutputStream s, byte b) throws Throwable {
260 byte[] bytes = new byte[4095];
261 Arrays.fill(bytes, b);
262 s.write(bytes);
263 }
264
265 static void checkPermissionDenied(ProcessBuilder pb) {
266 try {
267 pb.start();
268 fail("Expected IOException not thrown");
269 } catch (IOException e) {
270 String m = e.getMessage();
271 if (EnglishUnix.is() &&
272 ! matches(m, "Permission denied"))
273 unexpected(e);
274 } catch (Throwable t) { unexpected(t); }
275 }
276
277 public static class JavaChild {
278 public static void main(String args[]) throws Throwable {
279 String action = args[0];
280 if (action.equals("sleep")) {
281 Thread.sleep(10 * 60 * 1000L);
282 } else if (action.equals("testIO")) {
283 String expected = "standard input";
284 char[] buf = new char[expected.length()+1];
285 int n = new InputStreamReader(System.in).read(buf,0,buf.length);
286 if (n != expected.length())
287 System.exit(5);
288 if (! new String(buf,0,n).equals(expected))
289 System.exit(5);
290 System.err.print("standard error");
291 System.out.print("standard output");
292 } else if (action.equals("testInheritIO")) {
293 List<String> childArgs = new ArrayList<String>(javaChildArgs);
294 childArgs.add("testIO");
295 ProcessBuilder pb = new ProcessBuilder(childArgs);
296 pb.inheritIO();
297 ProcessResults r = run(pb);
298 if (! r.out().equals(""))
299 System.exit(7);
300 if (! r.err().equals(""))
301 System.exit(8);
302 if (r.exitValue() != 0)
303 System.exit(9);
304 } else if (action.equals("System.getenv(String)")) {
305 String val = System.getenv(args[1]);
306 printUTF8(val == null ? "null" : val);
307 } else if (action.equals("System.getenv(\\u1234)")) {
308 String val = System.getenv("\u1234");
309 printUTF8(val == null ? "null" : val);
310 } else if (action.equals("System.getenv()")) {
311 printUTF8(getenvAsString(System.getenv()));
312 } else if (action.equals("ArrayOOME")) {
313 Object dummy;
314 switch(new Random().nextInt(3)) {
315 case 0: dummy = new Integer[Integer.MAX_VALUE]; break;
316 case 1: dummy = new double[Integer.MAX_VALUE]; break;
317 case 2: dummy = new byte[Integer.MAX_VALUE][]; break;
318 default: throw new InternalError();
319 }
320 } else if (action.equals("pwd")) {
321 printUTF8(new File(System.getProperty("user.dir"))
322 .getCanonicalPath());
323 } else if (action.equals("print4095")) {
324 print4095(System.out, (byte) '!');
325 print4095(System.err, (byte) 'E');
326 System.exit(5);
327 } else if (action.equals("OutErr")) {
328
329
330
331
332 System.out.print("out");
333 System.err.print("err");
334 System.out.print("out");
335 System.err.print("err");
336 } else if (action.equals("null PATH")) {
337 equal(System.getenv("PATH"), null);
338 check(new File("/bin/true").exists());
339 check(new File("/bin/false").exists());
340 ProcessBuilder pb1 = new ProcessBuilder();
341 ProcessBuilder pb2 = new ProcessBuilder();
342 pb2.environment().put("PATH", "anyOldPathIgnoredAnyways");
343 ProcessResults r;
344
345 for (final ProcessBuilder pb :
346 new ProcessBuilder[] {pb1, pb2}) {
347 pb.command("true");
348 equal(run(pb).exitValue(), True.exitValue());
349
350 pb.command("false");
351 equal(run(pb).exitValue(), False.exitValue());
352 }
353
354 if (failed != 0) throw new Error("null PATH");
355 } else if (action.equals("PATH search algorithm")) {
356 equal(System.getenv("PATH"), "dir1:dir2:");
357 check(new File("/bin/true").exists());
358 check(new File("/bin/false").exists());
359 String[] cmd = {"prog"};
360 ProcessBuilder pb1 = new ProcessBuilder(cmd);
361 ProcessBuilder pb2 = new ProcessBuilder(cmd);
362 ProcessBuilder pb3 = new ProcessBuilder(cmd);
363 pb2.environment().put("PATH", "anyOldPathIgnoredAnyways");
364 pb3.environment().remove("PATH");
365
366 for (final ProcessBuilder pb :
367 new ProcessBuilder[] {pb1, pb2, pb3}) {
368 try {
369
370 try {
371 pb.start();
372 fail("Expected IOException not thrown");
373 } catch (IOException e) {
374 String m = e.getMessage();
375 if (EnglishUnix.is() &&
376 ! matches(m, "No such file"))
377 unexpected(e);
378 } catch (Throwable t) { unexpected(t); }
379
380
381 new File("dir1").mkdirs();
382 new File("dir2").mkdirs();
383 try {
384 pb.start();
385 fail("Expected IOException not thrown");
386 } catch (IOException e) {
387 String m = e.getMessage();
388 if (EnglishUnix.is() &&
389 ! matches(m, "No such file"))
390 unexpected(e);
391 } catch (Throwable t) { unexpected(t); }
392
393
394
395 new File("dir1/prog").mkdirs();
396 checkPermissionDenied(pb);
397
398
399 copy("/bin/true", "dir2/prog");
400 equal(run(pb).exitValue(), True.exitValue());
401 new File("dir1/prog").delete();
402 new File("dir2/prog").delete();
403
404 new File("dir2/prog").mkdirs();
405 copy("/bin/true", "dir1/prog");
406 equal(run(pb).exitValue(), True.exitValue());
407
408
409
410
411
412 new File("dir1/prog").delete();
413 new File("dir2/prog").delete();
414 for (String[] command :
415 new String[][] {
416 new String[] {"./prog"},
417 cmd}) {
418 pb.command(command);
419 File prog = new File("./prog");
420
421 copy("/bin/true", "./prog");
422 equal(run(pb).exitValue(),
423 True.exitValue());
424 copy("/bin/false", "./prog");
425 equal(run(pb).exitValue(),
426 False.exitValue());
427 prog.delete();
428
429 setFileContents(prog, "#!/bin/true\n");
430 prog.setExecutable(true);
431 equal(run(pb).exitValue(),
432 True.exitValue());
433 prog.delete();
434 setFileContents(prog, "#!/bin/false\n");
435 prog.setExecutable(true);
436 equal(run(pb).exitValue(),
437 False.exitValue());
438
439 setFileContents(prog, "exec /bin/true\n");
440 prog.setExecutable(true);
441 equal(run(pb).exitValue(),
442 True.exitValue());
443 prog.delete();
444 setFileContents(prog, "exec /bin/false\n");
445 prog.setExecutable(true);
446 equal(run(pb).exitValue(),
447 False.exitValue());
448 prog.delete();
449 }
450
451
452 File dir1Prog = new File("dir1/prog");
453 dir1Prog.delete();
454 pb.command(new String[] {"prog", "world"});
455 setFileContents(dir1Prog, "#!/bin/echo hello\n");
456 checkPermissionDenied(pb);
457 dir1Prog.setExecutable(true);
458 equal(run(pb).out(), "hello dir1/prog world\n");
459 equal(run(pb).exitValue(), True.exitValue());
460 dir1Prog.delete();
461 pb.command(cmd);
462
463
464 setFileContents(dir1Prog, "/bin/echo \"$@\"\n");
465 pb.command(new String[] {"prog", "hello", "world"});
466 checkPermissionDenied(pb);
467 dir1Prog.setExecutable(true);
468 equal(run(pb).out(), "hello world\n");
469 equal(run(pb).exitValue(), True.exitValue());
470 dir1Prog.delete();
471 pb.command(cmd);
472
473
474
475 new File("dir1/prog").delete();
476 new File("dir2/prog").delete();
477 new File("prog").delete();
478 new File("dir3").mkdirs();
479 copy("/bin/true", "dir1/prog");
480 copy("/bin/false", "dir3/prog");
481 pb.environment().put("PATH","dir3");
482 equal(run(pb).exitValue(), True.exitValue());
483 copy("/bin/true", "dir3/prog");
484 copy("/bin/false", "dir1/prog");
485 equal(run(pb).exitValue(), False.exitValue());
486
487 } finally {
488
489 new File("dir1/prog").delete();
490 new File("dir2/prog").delete();
491 new File("dir3/prog").delete();
492 new File("dir1").delete();
493 new File("dir2").delete();
494 new File("dir3").delete();
495 new File("prog").delete();
496 }
497 }
498
499 if (failed != 0) throw new Error("PATH search algorithm");
500 }
501 else throw new Error("JavaChild invocation error");
502 }
503 }
504
505 private static void copy(String src, String dst) {
506 system("/bin/cp", "-fp", src, dst);
507 }
508
509 private static void system(String... command) {
510 try {
511 ProcessBuilder pb = new ProcessBuilder(command);
512 ProcessResults r = run(pb.start());
513 equal(r.exitValue(), 0);
514 equal(r.out(), "");
515 equal(r.err(), "");
516 } catch (Throwable t) { unexpected(t); }
517 }
518
519 private static String javaChildOutput(ProcessBuilder pb, String...args) {
520 List<String> list = new ArrayList<String>(javaChildArgs);
521 for (String arg : args)
522 list.add(arg);
523 pb.command(list);
524 return commandOutput(pb);
525 }
526
527 private static String getenvInChild(ProcessBuilder pb) {
528 return javaChildOutput(pb, "System.getenv()");
529 }
530
531 private static String getenvInChild1234(ProcessBuilder pb) {
532 return javaChildOutput(pb, "System.getenv(\\u1234)");
533 }
534
535 private static String getenvInChild(ProcessBuilder pb, String name) {
536 return javaChildOutput(pb, "System.getenv(String)", name);
537 }
538
539 private static String pwdInChild(ProcessBuilder pb) {
540 return javaChildOutput(pb, "pwd");
541 }
542
543 private static final String javaExe =
544 System.getProperty("java.home") +
545 File.separator + "bin" + File.separator + "java";
546
547 private static final String classpath =
548 System.getProperty("java.class.path");
549
550 private static final List<String> javaChildArgs =
551 Arrays.asList(new String[]
552 { javaExe, "-classpath", absolutifyPath(classpath),
553 "Basic$JavaChild"});
554
555 private static void testEncoding(String encoding, String tested) {
556 try {
557
558
559 if (new String(tested.getBytes()).equals(tested)) {
560 out.println("Testing " + encoding + " environment values");
561 ProcessBuilder pb = new ProcessBuilder();
562 pb.environment().put("ASCIINAME",tested);
563 equal(getenvInChild(pb,"ASCIINAME"), tested);
564 }
565 } catch (Throwable t) { unexpected(t); }
566 }
567
568 static class Windows {
569 public static boolean is() { return is; }
570 private static final boolean is =
571 System.getProperty("os.name").startsWith("Windows");
572 }
573
574 static class Unix {
575 public static boolean is() { return is; }
576 private static final boolean is =
577 (! Windows.is() &&
578 new File("/bin/sh").exists() &&
579 new File("/bin/true").exists() &&
580 new File("/bin/false").exists());
581 }
582
583 static class UnicodeOS {
584 public static boolean is() { return is; }
585 private static final String osName = System.getProperty("os.name");
586 private static final boolean is =
587
588 osName.startsWith("Windows") &&
589 ! osName.startsWith("Windows 9") &&
590 ! osName.equals("Windows Me");
591 }
592
593 static class True {
594 public static int exitValue() { return 0; }
595 }
596
597 private static class False {
598 public static int exitValue() { return exitValue; }
599 private static final int exitValue = exitValue0();
600 private static int exitValue0() {
601
602 try {
603 if (! Unix.is())
604 return -1;
605 else {
606 int rc = new ProcessBuilder("/bin/false")
607 .start().waitFor();
608 check(rc != 0);
609 return rc;
610 }
611 } catch (Throwable t) { unexpected(t); return -1; }
612 }
613 }
614
615 static class EnglishUnix {
616 private final static Boolean is =
617 (! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
618
619 private static boolean isEnglish(String envvar) {
620 String val = getenv(envvar);
621 return (val == null) || val.matches("en.*");
622 }
623
624
625 static boolean is() { return is; }
626 }
627
628 private static boolean matches(String str, String regex) {
629 return Pattern.compile(regex).matcher(str).find();
630 }
631
632 private static String sortByLinesWindowsly(String text) {
633 String[] lines = text.split("\n");
634 Arrays.sort(lines, new WindowsComparator());
635 StringBuilder sb = new StringBuilder();
636 for (String line : lines)
637 sb.append(line).append("\n");
638 return sb.toString();
639 }
640
641 private static void checkMapSanity(Map<String,String> map) {
642 try {
643 Set<String> keySet = map.keySet();
644 Collection<String> values = map.values();
645 Set<Map.Entry<String,String>> entrySet = map.entrySet();
646
647 equal(entrySet.size(), keySet.size());
648 equal(entrySet.size(), values.size());
649
650 StringBuilder s1 = new StringBuilder();
651 for (Map.Entry<String,String> e : entrySet)
652 s1.append(e.getKey() + "=" + e.getValue() + "\n");
653
654 StringBuilder s2 = new StringBuilder();
655 for (String var : keySet)
656 s2.append(var + "=" + map.get(var) + "\n");
657
658 equal(s1.toString(), s2.toString());
659
660 Iterator<String> kIter = keySet.iterator();
661 Iterator<String> vIter = values.iterator();
662 Iterator<Map.Entry<String,String>> eIter = entrySet.iterator();
663
664 while (eIter.hasNext()) {
665 Map.Entry<String,String> entry = eIter.next();
666 String key = kIter.next();
667 String value = vIter.next();
668 check(entrySet.contains(entry));
669 check(keySet.contains(key));
670 check(values.contains(value));
671 check(map.containsKey(key));
672 check(map.containsValue(value));
673 equal(entry.getKey(), key);
674 equal(entry.getValue(), value);
675 }
676 check(! kIter.hasNext() &&
677 ! vIter.hasNext());
678
679 } catch (Throwable t) { unexpected(t); }
680 }
681
682 private static void checkMapEquality(Map<String,String> map1,
683 Map<String,String> map2) {
684 try {
685 equal(map1.size(), map2.size());
686 equal(map1.isEmpty(), map2.isEmpty());
687 for (String key : map1.keySet()) {
688 equal(map1.get(key), map2.get(key));
689 check(map2.keySet().contains(key));
690 }
691 equal(map1, map2);
692 equal(map2, map1);
693 equal(map1.entrySet(), map2.entrySet());
694 equal(map2.entrySet(), map1.entrySet());
695 equal(map1.keySet(), map2.keySet());
696 equal(map2.keySet(), map1.keySet());
697
698 equal(map1.hashCode(), map2.hashCode());
699 equal(map1.entrySet().hashCode(), map2.entrySet().hashCode());
700 equal(map1.keySet().hashCode(), map2.keySet().hashCode());
701 } catch (Throwable t) { unexpected(t); }
702 }
703
704 static void checkRedirects(ProcessBuilder pb,
705 Redirect in, Redirect out, Redirect err) {
706 equal(pb.redirectInput(), in);
707 equal(pb.redirectOutput(), out);
708 equal(pb.redirectError(), err);
709 }
710
711 static void redirectIO(ProcessBuilder pb,
712 Redirect in, Redirect out, Redirect err) {
713 pb.redirectInput(in);
714 pb.redirectOutput(out);
715 pb.redirectError(err);
716 }
717
718 static void setFileContents(File file, String contents) {
719 try {
720 Writer w = new FileWriter(file);
721 w.write(contents);
722 w.close();
723 } catch (Throwable t) { unexpected(t); }
724 }
725
726 static String fileContents(File file) {
727 try {
728 Reader r = new FileReader(file);
729 StringBuilder sb = new StringBuilder();
730 char[] buffer = new char[1024];
731 int n;
732 while ((n = r.read(buffer)) != -1)
733 sb.append(buffer,0,n);
734 r.close();
735 return new String(sb);
736 } catch (Throwable t) { unexpected(t); return ""; }
737 }
738
739 static void testIORedirection() throws Throwable {
740 final File ifile = new File("ifile");
741 final File ofile = new File("ofile");
742 final File efile = new File("efile");
743 ifile.delete();
744 ofile.delete();
745 efile.delete();
746
747
748
749
750 Redirect[] redirects =
751 { PIPE,
752 INHERIT,
753 Redirect.from(ifile),
754 Redirect.to(ifile),
755 Redirect.appendTo(ifile),
756 Redirect.from(ofile),
757 Redirect.to(ofile),
758 Redirect.appendTo(ofile),
759 };
760 for (int i = 0; i < redirects.length; i++)
761 for (int j = 0; j < redirects.length; j++)
762 equal(redirects[i].equals(redirects[j]), (i == j));
763
764
765
766
767 equal(PIPE.type(), Redirect.Type.PIPE);
768 equal(PIPE.toString(), "PIPE");
769 equal(PIPE.file(), null);
770
771 equal(INHERIT.type(), Redirect.Type.INHERIT);
772 equal(INHERIT.toString(), "INHERIT");
773 equal(INHERIT.file(), null);
774
775 equal(Redirect.from(ifile).type(), Redirect.Type.READ);
776 equal(Redirect.from(ifile).toString(),
777 "redirect to read from file \"ifile\"");
778 equal(Redirect.from(ifile).file(), ifile);
779 equal(Redirect.from(ifile),
780 Redirect.from(ifile));
781 equal(Redirect.from(ifile).hashCode(),
782 Redirect.from(ifile).hashCode());
783
784 equal(Redirect.to(ofile).type(), Redirect.Type.WRITE);
785 equal(Redirect.to(ofile).toString(),
786 "redirect to write to file \"ofile\"");
787 equal(Redirect.to(ofile).file(), ofile);
788 equal(Redirect.to(ofile),
789 Redirect.to(ofile));
790 equal(Redirect.to(ofile).hashCode(),
791 Redirect.to(ofile).hashCode());
792
793 equal(Redirect.appendTo(ofile).type(), Redirect.Type.APPEND);
794 equal(Redirect.appendTo(efile).toString(),
795 "redirect to append to file \"efile\"");
796 equal(Redirect.appendTo(efile).file(), efile);
797 equal(Redirect.appendTo(efile),
798 Redirect.appendTo(efile));
799 equal(Redirect.appendTo(efile).hashCode(),
800 Redirect.appendTo(efile).hashCode());
801
802
803
804
805 List<String> childArgs = new ArrayList<String>(javaChildArgs);
806 childArgs.add("testIO");
807 final ProcessBuilder pb = new ProcessBuilder(childArgs);
808 checkRedirects(pb, PIPE, PIPE, PIPE);
809
810
811
812
813 pb.inheritIO();
814 checkRedirects(pb, INHERIT, INHERIT, INHERIT);
815
816
817
818
819 pb.redirectInput(ifile);
820 equal(pb.redirectInput().file(), ifile);
821 equal(pb.redirectInput(), Redirect.from(ifile));
822
823 pb.redirectOutput(ofile);
824 equal(pb.redirectOutput().file(), ofile);
825 equal(pb.redirectOutput(), Redirect.to(ofile));
826
827 pb.redirectError(efile);
828 equal(pb.redirectError().file(), efile);
829 equal(pb.redirectError(), Redirect.to(efile));
830
831 THROWS(IllegalArgumentException.class,
832 new Fun(){void f() {
833 pb.redirectInput(Redirect.to(ofile)); }},
834 new Fun(){void f() {
835 pb.redirectInput(Redirect.appendTo(ofile)); }},
836 new Fun(){void f() {
837 pb.redirectOutput(Redirect.from(ifile)); }},
838 new Fun(){void f() {
839 pb.redirectError(Redirect.from(ifile)); }});
840
841 THROWS(IOException.class,
842
843 new Fun(){void f() throws Throwable { pb.start(); }});
844 setFileContents(ifile, "standard input");
845
846
847
848
849 {
850 ProcessResults r = run(pb);
851 equal(r.exitValue(), 0);
852 equal(fileContents(ofile), "standard output");
853 equal(fileContents(efile), "standard error");
854 equal(r.out(), "");
855 equal(r.err(), "");
856 ofile.delete();
857 efile.delete();
858 }
859
860
861
862
863 {
864 pb.redirectErrorStream(true);
865 ProcessResults r = run(pb);
866 equal(r.exitValue(), 0);
867 equal(fileContents(ofile),
868 "standard error" + "standard output");
869 equal(fileContents(efile), "");
870 equal(r.out(), "");
871 equal(r.err(), "");
872 ofile.delete();
873 efile.delete();
874 }
875
876
877
878
879 {
880 setFileContents(ofile, "ofile-contents");
881 setFileContents(efile, "efile-contents");
882 pb.redirectOutput(Redirect.appendTo(ofile));
883 pb.redirectError(Redirect.appendTo(efile));
884 pb.redirectErrorStream(false);
885 ProcessResults r = run(pb);
886 equal(r.exitValue(), 0);
887 equal(fileContents(ofile),
888 "ofile-contents" + "standard output");
889 equal(fileContents(efile),
890 "efile-contents" + "standard error");
891 equal(r.out(), "");
892 equal(r.err(), "");
893 ofile.delete();
894 efile.delete();
895 }
896
897
898
899
900 {
901 setFileContents(ofile, "ofile-contents");
902 setFileContents(efile, "efile-contents");
903 pb.redirectOutput(ofile);
904 pb.redirectError(Redirect.to(efile));
905 ProcessResults r = run(pb);
906 equal(r.exitValue(), 0);
907 equal(fileContents(ofile), "standard output");
908 equal(fileContents(efile), "standard error");
909 equal(r.out(), "");
910 equal(r.err(), "");
911 ofile.delete();
912 efile.delete();
913 }
914
915
916
917
918 {
919 setFileContents(ofile, "ofile-contents");
920 setFileContents(efile, "efile-contents");
921 Redirect appender = Redirect.appendTo(ofile);
922 pb.redirectOutput(appender);
923 pb.redirectError(appender);
924 ProcessResults r = run(pb);
925 equal(r.exitValue(), 0);
926 equal(fileContents(ofile),
927 "ofile-contents" +
928 "standard error" +
929 "standard output");
930 equal(fileContents(efile), "efile-contents");
931 equal(r.out(), "");
932 equal(r.err(), "");
933 ifile.delete();
934 ofile.delete();
935 efile.delete();
936 }
937
938
939
940
941
942
943 {
944 redirectIO(pb, PIPE, PIPE, PIPE);
945 List<String> command = pb.command();
946 command.set(command.size() - 1, "testInheritIO");
947 Process p = pb.start();
948 new PrintStream(p.getOutputStream()).print("standard input");
949 p.getOutputStream().close();
950 ProcessResults r = run(p);
951 equal(r.exitValue(), 0);
952 equal(r.out(), "standard output");
953 equal(r.err(), "standard error");
954 }
955
956
957
958
959
960
961
962 final File tmpFile = File.createTempFile("Basic", "tmp");
963 setFileContents(tmpFile, "standard input");
964
965 final Policy policy = new Policy();
966 Policy.setPolicy(policy);
967 System.setSecurityManager(new SecurityManager());
968 try {
969 final Permission xPermission
970 = new FilePermission("<<ALL FILES>>", "execute");
971 final Permission rxPermission
972 = new FilePermission("<<ALL FILES>>", "read,execute");
973 final Permission wxPermission
974 = new FilePermission("<<ALL FILES>>", "write,execute");
975 final Permission rwxPermission
976 = new FilePermission("<<ALL FILES>>", "read,write,execute");
977
978 THROWS(SecurityException.class,
979 new Fun() { void f() throws IOException {
980 policy.setPermissions(xPermission);
981 redirectIO(pb, from(tmpFile), PIPE, PIPE);
982 pb.start();}},
983 new Fun() { void f() throws IOException {
984 policy.setPermissions(rxPermission);
985 redirectIO(pb, PIPE, to(ofile), PIPE);
986 pb.start();}},
987 new Fun() { void f() throws IOException {
988 policy.setPermissions(rxPermission);
989 redirectIO(pb, PIPE, PIPE, to(efile));
990 pb.start();}});
991
992 {
993 policy.setPermissions(rxPermission);
994 redirectIO(pb, from(tmpFile), PIPE, PIPE);
995 ProcessResults r = run(pb);
996 equal(r.out(), "standard output");
997 equal(r.err(), "standard error");
998 }
999
1000 {
1001 policy.setPermissions(wxPermission);
1002 redirectIO(pb, PIPE, to(ofile), to(efile));
1003 Process p = pb.start();
1004 new PrintStream(p.getOutputStream()).print("standard input");
1005 p.getOutputStream().close();
1006 ProcessResults r = run(p);
1007 policy.setPermissions(rwxPermission);
1008 equal(fileContents(ofile), "standard output");
1009 equal(fileContents(efile), "standard error");
1010 }
1011
1012 {
1013 policy.setPermissions(rwxPermission);
1014 redirectIO(pb, from(tmpFile), to(ofile), to(efile));
1015 ProcessResults r = run(pb);
1016 policy.setPermissions(rwxPermission);
1017 equal(fileContents(ofile), "standard output");
1018 equal(fileContents(efile), "standard error");
1019 }
1020
1021 } finally {
1022 policy.setPermissions(new RuntimePermission("setSecurityManager"));
1023 System.setSecurityManager(null);
1024 tmpFile.delete();
1025 ifile.delete();
1026 ofile.delete();
1027 efile.delete();
1028 }
1029 }
1030
1031 private static void realMain(String[] args) throws Throwable {
1032 if (Windows.is())
1033 System.out.println("This appears to be a Windows system.");
1034 if (Unix.is())
1035 System.out.println("This appears to be a Unix system.");
1036 if (UnicodeOS.is())
1037 System.out.println("This appears to be a Unicode-based OS.");
1038
1039 try { testIORedirection(); }
1040 catch (Throwable t) { unexpected(t); }
1041
1042
1043
1044
1045 try {
1046 ProcessBuilder pb = new ProcessBuilder();
1047 Map<String,String> environ = pb.environment();
1048
1049
1050 environ.put("QUUX", "BAR");
1051 equal(environ.get("QUUX"), "BAR");
1052 equal(getenvInChild(pb,"QUUX"), "BAR");
1053
1054
1055 environ.put("QUUX","bear");
1056 equal(environ.get("QUUX"), "bear");
1057 equal(getenvInChild(pb,"QUUX"), "bear");
1058 checkMapSanity(environ);
1059
1060
1061 environ.remove("QUUX");
1062 equal(environ.get("QUUX"), null);
1063 equal(getenvInChild(pb,"QUUX"), "null");
1064 checkMapSanity(environ);
1065
1066
1067 environ.remove("QUUX");
1068 equal(environ.get("QUUX"), null);
1069 equal(getenvInChild(pb,"QUUX"), "null");
1070 checkMapSanity(environ);
1071 } catch (Throwable t) { unexpected(t); }
1072
1073
1074
1075
1076 try {
1077 ProcessBuilder pb = new ProcessBuilder();
1078 pb.environment().clear();
1079 String expected = Windows.is() ? "SystemRoot="+systemRoot+",": "";
1080 if (Windows.is()) {
1081 pb.environment().put("SystemRoot", systemRoot);
1082 }
1083 equal(getenvInChild(pb), expected);
1084 } catch (Throwable t) { unexpected(t); }
1085
1086
1087
1088
1089 THROWS(UnsupportedOperationException.class,
1090 new Fun(){void f(){ getenv().put("FOO","BAR");}},
1091 new Fun(){void f(){ getenv().remove("PATH");}},
1092 new Fun(){void f(){ getenv().keySet().remove("PATH");}},
1093 new Fun(){void f(){ getenv().values().remove("someValue");}});
1094
1095 try {
1096 Collection<Map.Entry<String,String>> c = getenv().entrySet();
1097 if (! c.isEmpty())
1098 try {
1099 c.iterator().next().setValue("foo");
1100 fail("Expected UnsupportedOperationException not thrown");
1101 } catch (UnsupportedOperationException e) {}
1102 } catch (Throwable t) { unexpected(t); }
1103
1104
1105
1106
1107 try {
1108 check(System.getenv() == System.getenv());
1109 } catch (Throwable t) { unexpected(t); }
1110
1111
1112
1113
1114
1115 {
1116 final Map<String,String> m = new ProcessBuilder().environment();
1117 THROWS(IllegalArgumentException.class,
1118 new Fun(){void f(){ m.put("FOO=","BAR");}},
1119 new Fun(){void f(){ m.put("FOO\u0000","BAR");}},
1120 new Fun(){void f(){ m.put("FOO","BAR\u0000");}});
1121 }
1122
1123
1124
1125
1126 THROWS(NullPointerException.class,
1127 new Fun(){void f(){
1128 new ProcessBuilder((List<String>)null);}},
1129 new Fun(){void f(){
1130 new ProcessBuilder().command((List<String>)null);}});
1131
1132
1133
1134
1135 try {
1136 List<String> command = new ArrayList<String>();
1137 ProcessBuilder pb = new ProcessBuilder(command);
1138 check(pb.command() == command);
1139 List<String> command2 = new ArrayList<String>(2);
1140 command2.add("foo");
1141 command2.add("bar");
1142 pb.command(command2);
1143 check(pb.command() == command2);
1144 pb.command("foo", "bar");
1145 check(pb.command() != command2 && pb.command().equals(command2));
1146 pb.command(command2);
1147 command2.add("baz");
1148 equal(pb.command().get(2), "baz");
1149 } catch (Throwable t) { unexpected(t); }
1150
1151
1152
1153
1154 THROWS(IndexOutOfBoundsException.class,
1155 new Fun() { void f() throws IOException {
1156 new ProcessBuilder().start();}},
1157 new Fun() { void f() throws IOException {
1158 new ProcessBuilder(new ArrayList<String>()).start();}},
1159 new Fun() { void f() throws IOException {
1160 Runtime.getRuntime().exec(new String[]{});}});
1161
1162
1163
1164
1165 THROWS(NullPointerException.class,
1166 new Fun() { void f() throws IOException {
1167 new ProcessBuilder("foo",null,"bar").start();}},
1168 new Fun() { void f() throws IOException {
1169 new ProcessBuilder((String)null).start();}},
1170 new Fun() { void f() throws IOException {
1171 new ProcessBuilder(new String[]{null}).start();}},
1172 new Fun() { void f() throws IOException {
1173 new ProcessBuilder(new String[]{"foo",null,"bar"}).start();}});
1174
1175
1176
1177
1178 try {
1179 new ProcessBuilder().command().add("foo");
1180 new ProcessBuilder("bar").command().add("foo");
1181 new ProcessBuilder(new String[]{"1","2"}).command().add("3");
1182 } catch (Throwable t) { unexpected(t); }
1183
1184
1185
1186
1187 try {
1188 final Map<String,String> env = new ProcessBuilder().environment();
1189 THROWS(NullPointerException.class,
1190 new Fun(){void f(){ env.put("foo",null);}},
1191 new Fun(){void f(){ env.put(null,"foo");}},
1192 new Fun(){void f(){ env.remove(null);}},
1193 new Fun(){void f(){
1194 for (Map.Entry<String,String> e : env.entrySet())
1195 e.setValue(null);}},
1196 new Fun() { void f() throws IOException {
1197 Runtime.getRuntime().exec(new String[]{"foo"},
1198 new String[]{null});}});
1199 } catch (Throwable t) { unexpected(t); }
1200
1201
1202
1203
1204 try {
1205 final Map<String,String> env = new ProcessBuilder().environment();
1206 THROWS(ClassCastException.class,
1207 new Fun(){void f(){ env.remove(TRUE);}},
1208 new Fun(){void f(){ env.keySet().remove(TRUE);}},
1209 new Fun(){void f(){ env.values().remove(TRUE);}},
1210 new Fun(){void f(){ env.entrySet().remove(TRUE);}});
1211 } catch (Throwable t) { unexpected(t); }
1212
1213
1214
1215
1216 try {
1217 List<Map<String,String>> envs =
1218 new ArrayList<Map<String,String>>(2);
1219 envs.add(System.getenv());
1220 envs.add(new ProcessBuilder().environment());
1221 for (final Map<String,String> env : envs) {
1222
1223
1224
1225 THROWS(NullPointerException.class,
1226 new Fun(){void f(){ getenv(null);}},
1227 new Fun(){void f(){ env.get(null);}},
1228 new Fun(){void f(){ env.containsKey(null);}},
1229 new Fun(){void f(){ env.containsValue(null);}},
1230 new Fun(){void f(){ env.keySet().contains(null);}},
1231 new Fun(){void f(){ env.values().contains(null);}});
1232
1233
1234
1235
1236 THROWS(ClassCastException.class,
1237 new Fun(){void f(){ env.get(TRUE);}},
1238 new Fun(){void f(){ env.containsKey(TRUE);}},
1239 new Fun(){void f(){ env.containsValue(TRUE);}},
1240 new Fun(){void f(){ env.keySet().contains(TRUE);}},
1241 new Fun(){void f(){ env.values().contains(TRUE);}});
1242
1243
1244
1245
1246 equal(env.get("\u0000"), null);
1247 check(! env.containsKey("\u0000"));
1248 check(! env.containsValue("\u0000"));
1249 check(! env.keySet().contains("\u0000"));
1250 check(! env.values().contains("\u0000"));
1251 }
1252
1253 } catch (Throwable t) { unexpected(t); }
1254
1255 try {
1256 final Set<Map.Entry<String,String>> entrySet =
1257 new ProcessBuilder().environment().entrySet();
1258 THROWS(NullPointerException.class,
1259 new Fun(){void f(){ entrySet.contains(null);}});
1260 THROWS(ClassCastException.class,
1261 new Fun(){void f(){ entrySet.contains(TRUE);}},
1262 new Fun(){void f(){
1263 entrySet.contains(
1264 new SimpleImmutableEntry<Boolean,String>(TRUE,""));}});
1265
1266 check(! entrySet.contains
1267 (new SimpleImmutableEntry<String,String>("", "")));
1268 } catch (Throwable t) { unexpected(t); }
1269
1270
1271
1272
1273 try {
1274 ProcessBuilder pb = new ProcessBuilder();
1275 File foo = new File("foo");
1276 equal(pb.directory(), null);
1277 equal(pb.directory(foo).directory(), foo);
1278 equal(pb.directory(null).directory(), null);
1279 } catch (Throwable t) { unexpected(t); }
1280
1281
1282
1283
1284 try {
1285 testEncoding("ASCII", "xyzzy");
1286 testEncoding("Latin1", "\u00f1\u00e1");
1287 testEncoding("Unicode", "\u22f1\u11e1");
1288 } catch (Throwable t) { unexpected(t); }
1289
1290
1291
1292
1293 testVariableDeleter(new EnvironmentFrobber() {
1294 public void doIt(Map<String,String> environ) {
1295 environ.remove("Foo");}});
1296
1297 testVariableDeleter(new EnvironmentFrobber() {
1298 public void doIt(Map<String,String> environ) {
1299 environ.keySet().remove("Foo");}});
1300
1301 testVariableDeleter(new EnvironmentFrobber() {
1302 public void doIt(Map<String,String> environ) {
1303 environ.values().remove("BAAR");}});
1304
1305 testVariableDeleter(new EnvironmentFrobber() {
1306 public void doIt(Map<String,String> environ) {
1307
1308
1309 Map<String,String> environ2
1310 = new ProcessBuilder().environment();
1311 environ2.clear();
1312 environ2.put("Foo","BAAR");
1313
1314 Map.Entry<String,String> e
1315 = environ2.entrySet().iterator().next();
1316 environ.entrySet().remove(e);}});
1317
1318 testVariableDeleter(new EnvironmentFrobber() {
1319 public void doIt(Map<String,String> environ) {
1320 Map.Entry<String,String> victim = null;
1321 for (Map.Entry<String,String> e : environ.entrySet())
1322 if (e.getKey().equals("Foo"))
1323 victim = e;
1324 if (victim != null)
1325 environ.entrySet().remove(victim);}});
1326
1327 testVariableDeleter(new EnvironmentFrobber() {
1328 public void doIt(Map<String,String> environ) {
1329 Iterator<String> it = environ.keySet().iterator();
1330 while (it.hasNext()) {
1331 String val = it.next();
1332 if (val.equals("Foo"))
1333 it.remove();}}});
1334
1335 testVariableDeleter(new EnvironmentFrobber() {
1336 public void doIt(Map<String,String> environ) {
1337 Iterator<Map.Entry<String,String>> it
1338 = environ.entrySet().iterator();
1339 while (it.hasNext()) {
1340 Map.Entry<String,String> e = it.next();
1341 if (e.getKey().equals("Foo"))
1342 it.remove();}}});
1343
1344 testVariableDeleter(new EnvironmentFrobber() {
1345 public void doIt(Map<String,String> environ) {
1346 Iterator<String> it = environ.values().iterator();
1347 while (it.hasNext()) {
1348 String val = it.next();
1349 if (val.equals("BAAR"))
1350 it.remove();}}});
1351
1352
1353
1354
1355 testVariableAdder(new EnvironmentFrobber() {
1356 public void doIt(Map<String,String> environ) {
1357 environ.put("Foo","Bahrein");}});
1358
1359
1360
1361
1362 testVariableModifier(new EnvironmentFrobber() {
1363 public void doIt(Map<String,String> environ) {
1364 environ.put("Foo","NewValue");}});
1365
1366 testVariableModifier(new EnvironmentFrobber() {
1367 public void doIt(Map<String,String> environ) {
1368 for (Map.Entry<String,String> e : environ.entrySet())
1369 if (e.getKey().equals("Foo"))
1370 e.setValue("NewValue");}});
1371
1372
1373
1374
1375 try {
1376 Map<String,String> environ = new ProcessBuilder().environment();
1377 int size = environ.size();
1378 checkSizes(environ, size);
1379
1380 environ.put("UnLiKeLYeNVIROmtNam", "someVal");
1381 checkSizes(environ, size+1);
1382
1383
1384 new ProcessBuilder().environment().clear();
1385
1386 environ.put("UnLiKeLYeNVIROmtNam", "someOtherVal");
1387 checkSizes(environ, size+1);
1388
1389 environ.remove("UnLiKeLYeNVIROmtNam");
1390 checkSizes(environ, size);
1391
1392 environ.clear();
1393 checkSizes(environ, 0);
1394
1395 environ.clear();
1396 checkSizes(environ, 0);
1397
1398 environ = new ProcessBuilder().environment();
1399 environ.keySet().clear();
1400 checkSizes(environ, 0);
1401
1402 environ = new ProcessBuilder().environment();
1403 environ.entrySet().clear();
1404 checkSizes(environ, 0);
1405
1406 environ = new ProcessBuilder().environment();
1407 environ.values().clear();
1408 checkSizes(environ, 0);
1409 } catch (Throwable t) { unexpected(t); }
1410
1411
1412
1413
1414 checkMapSanity(new ProcessBuilder().environment());
1415 checkMapSanity(System.getenv());
1416 checkMapEquality(new ProcessBuilder().environment(),
1417 new ProcessBuilder().environment());
1418
1419
1420
1421
1422
1423 try {
1424 Set<String> env1 = new HashSet<String>
1425 (Arrays.asList(nativeEnv((String[])null).split("\n")));
1426
1427 ProcessBuilder pb = new ProcessBuilder();
1428 pb.environment().put("QwErTyUiOp","AsDfGhJk");
1429
1430 Set<String> env2 = new HashSet<String>
1431 (Arrays.asList(nativeEnv(pb).split("\n")));
1432
1433 check(env2.size() == env1.size() + 1);
1434 env1.add("QwErTyUiOp=AsDfGhJk");
1435 check(env1.equals(env2));
1436 } catch (Throwable t) { unexpected(t); }
1437
1438
1439
1440
1441
1442 try {
1443 String systemRoot = "SystemRoot=" + System.getenv("SystemRoot");
1444
1445 String[]envp = {"FOO=BAR","BAZ=GORP","QUUX=",
1446 "+=+", "_=_", "~=~", systemRoot};
1447 String output = nativeEnv(envp);
1448 String expected = "+=+\nBAZ=GORP\nFOO=BAR\nQUUX=\n"+systemRoot+"\n_=_\n~=~\n";
1449
1450
1451 if (! Windows.is())
1452 output = sortByLinesWindowsly(output);
1453 equal(output, expected);
1454 } catch (Throwable t) { unexpected(t); }
1455
1456
1457
1458
1459
1460 try {
1461 if (Windows.is()) {
1462 String systemRoot = "SystemRoot=" + System.getenv("SystemRoot");
1463 String[]envp = {"FOO=BAR","BAZ=GORP","QUUX=",
1464 "+=+", "_=_", "~=~"};
1465 String output = nativeEnv(envp);
1466 String expected = "+=+\nBAZ=GORP\nFOO=BAR\nQUUX=\n"+systemRoot+"\n_=_\n~=~\n";
1467 equal(output, expected);
1468 }
1469 } catch (Throwable t) { unexpected(t); }
1470
1471
1472
1473
1474 try {
1475 for (Map.Entry<String,String> e : getenv().entrySet())
1476 equal(getenv(e.getKey()), e.getValue());
1477 } catch (Throwable t) { unexpected(t); }
1478
1479
1480
1481
1482 try {
1483 String canonicalUserDir =
1484 new File(System.getProperty("user.dir")).getCanonicalPath();
1485 String[] sdirs = new String[]
1486 {".", "..", "/", "/bin",
1487 "C:", "c:", "C:/", "c:\\", "\\", "\\bin",
1488 "c:\\windows ", "c:\\Program Files", "c:\\Program Files\\" };
1489 for (String sdir : sdirs) {
1490 File dir = new File(sdir);
1491 if (! (dir.isDirectory() && dir.exists()))
1492 continue;
1493 out.println("Testing directory " + dir);
1494
1495
1496 ProcessBuilder pb = new ProcessBuilder();
1497 equal(pb.directory(), null);
1498 equal(pwdInChild(pb), canonicalUserDir);
1499
1500 pb.directory(dir);
1501 equal(pb.directory(), dir);
1502 equal(pwdInChild(pb), dir.getCanonicalPath());
1503
1504 pb.directory(null);
1505 equal(pb.directory(), null);
1506 equal(pwdInChild(pb), canonicalUserDir);
1507
1508 pb.directory(dir);
1509 }
1510 } catch (Throwable t) { unexpected(t); }
1511
1512
1513
1514
1515 try {
1516 if (UnicodeOS.is()) {
1517 File dir = new File(System.getProperty("test.dir", "."),
1518 "ProcessBuilderDir\u4e00\u4e02");
1519 try {
1520 if (!dir.exists())
1521 dir.mkdir();
1522 out.println("Testing Unicode directory:" + dir);
1523 ProcessBuilder pb = new ProcessBuilder();
1524 pb.directory(dir);
1525 equal(pwdInChild(pb), dir.getCanonicalPath());
1526 } finally {
1527 if (dir.exists())
1528 dir.delete();
1529 }
1530 }
1531 } catch (Throwable t) { unexpected(t); }
1532
1533
1534
1535
1536
1537 try {
1538 List<String> list = new ArrayList<String>(javaChildArgs);
1539 list.add(1, String.format("-XX:OnOutOfMemoryError=%s -version",
1540 javaExe));
1541 list.add("ArrayOOME");
1542 ProcessResults r = run(new ProcessBuilder(list));
1543 check(r.out().contains("java.lang.OutOfMemoryError:"));
1544 check(r.out().contains(javaExe));
1545 check(r.err().contains(System.getProperty("java.version")));
1546 equal(r.exitValue(), 1);
1547 } catch (Throwable t) { unexpected(t); }
1548
1549
1550
1551
1552 if (Windows.is())
1553 try {
1554 out.println("Running case insensitve variable tests");
1555 for (String[] namePair :
1556 new String[][]
1557 { new String[]{"PATH","PaTh"},
1558 new String[]{"home","HOME"},
1559 new String[]{"SYSTEMROOT","SystemRoot"}}) {
1560 check((getenv(namePair[0]) == null &&
1561 getenv(namePair[1]) == null)
1562 ||
1563 getenv(namePair[0]).equals(getenv(namePair[1])),
1564 "Windows environment variables are not case insensitive");
1565 }
1566 } catch (Throwable t) { unexpected(t); }
1567
1568
1569
1570
1571 if (UnicodeOS.is())
1572 try {
1573 ProcessBuilder pb = new ProcessBuilder();
1574 pb.environment().put("\u1234","\u5678");
1575 pb.environment().remove("PATH");
1576 equal(getenvInChild1234(pb), "\u5678");
1577 } catch (Throwable t) { unexpected(t); }
1578
1579
1580
1581
1582
1583 try {
1584 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1585 childArgs.add("System.getenv()");
1586 String[] cmdp = childArgs.toArray(new String[childArgs.size()]);
1587 String[] envp;
1588 String[] envpWin = {"=ExitValue=3", "=C:=\\", "SystemRoot="+systemRoot};
1589 String[] envpOth = {"=ExitValue=3", "=C:=\\"};
1590 if (Windows.is()) {
1591 envp = envpWin;
1592 } else {
1593 envp = envpOth;
1594 }
1595 Process p = Runtime.getRuntime().exec(cmdp, envp);
1596 String expected = Windows.is() ? "=C:=\\,SystemRoot="+systemRoot+",=ExitValue=3," : "=C:=\\,";
1597 equal(commandOutput(p), expected);
1598 if (Windows.is()) {
1599 ProcessBuilder pb = new ProcessBuilder(childArgs);
1600 pb.environment().clear();
1601 pb.environment().put("SystemRoot", systemRoot);
1602 pb.environment().put("=ExitValue", "3");
1603 pb.environment().put("=C:", "\\");
1604 equal(commandOutput(pb), expected);
1605 }
1606 } catch (Throwable t) { unexpected(t); }
1607
1608
1609
1610
1611 try {
1612 String[] cmdp = {"echo"};
1613 String[] envp = {"Hello", "World"};
1614 Process p = Runtime.getRuntime().exec(cmdp, envp);
1615 equal(commandOutput(p), "\n");
1616 } catch (Throwable t) { unexpected(t); }
1617
1618
1619
1620
1621 try {
1622 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1623 childArgs.add("System.getenv()");
1624 String[] cmdp = childArgs.toArray(new String[childArgs.size()]);
1625 String[] envpWin = {"SystemRoot="+systemRoot, "LC_ALL=C\u0000\u0000",
1626 "FO\u0000=B\u0000R"};
1627 String[] envpOth = {"LC_ALL=C\u0000\u0000",
1628 "FO\u0000=B\u0000R"};
1629 String[] envp;
1630 if (Windows.is()) {
1631 envp = envpWin;
1632 } else {
1633 envp = envpOth;
1634 }
1635 Process p = Runtime.getRuntime().exec(cmdp, envp);
1636 check(commandOutput(p).equals(Windows.is() ? "SystemRoot="+systemRoot+",LC_ALL=C," : "LC_ALL=C,"),
1637 "Incorrect handling of envstrings containing NULs");
1638 } catch (Throwable t) { unexpected(t); }
1639
1640
1641
1642
1643 try {
1644 ProcessBuilder pb = new ProcessBuilder();
1645 equal(pb.redirectErrorStream(), false);
1646 equal(pb.redirectErrorStream(true), pb);
1647 equal(pb.redirectErrorStream(), true);
1648 equal(pb.redirectErrorStream(false), pb);
1649 equal(pb.redirectErrorStream(), false);
1650 } catch (Throwable t) { unexpected(t); }
1651
1652 try {
1653 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1654 childArgs.add("OutErr");
1655 ProcessBuilder pb = new ProcessBuilder(childArgs);
1656 {
1657 ProcessResults r = run(pb);
1658 equal(r.out(), "outout");
1659 equal(r.err(), "errerr");
1660 }
1661 {
1662 pb.redirectErrorStream(true);
1663 ProcessResults r = run(pb);
1664 equal(r.out(), "outerrouterr");
1665 equal(r.err(), "");
1666 }
1667 } catch (Throwable t) { unexpected(t); }
1668
1669 if (Unix.is()) {
1670
1671
1672
1673 try {
1674 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1675 childArgs.add("null PATH");
1676 ProcessBuilder pb = new ProcessBuilder(childArgs);
1677 pb.environment().remove("PATH");
1678 ProcessResults r = run(pb);
1679 equal(r.out(), "");
1680 equal(r.err(), "");
1681 equal(r.exitValue(), 0);
1682 } catch (Throwable t) { unexpected(t); }
1683
1684
1685
1686
1687 try {
1688 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1689 childArgs.add("PATH search algorithm");
1690 ProcessBuilder pb = new ProcessBuilder(childArgs);
1691 pb.environment().put("PATH", "dir1:dir2:");
1692 ProcessResults r = run(pb);
1693 equal(r.out(), "");
1694 equal(r.err(), "");
1695 equal(r.exitValue(), True.exitValue());
1696 } catch (Throwable t) { unexpected(t); }
1697
1698
1699
1700
1701 try {
1702 new File("suBdiR").mkdirs();
1703 copy("/bin/true", "suBdiR/unliKely");
1704 final ProcessBuilder pb =
1705 new ProcessBuilder(new String[]{"unliKely"});
1706 pb.environment().put("PATH", "suBdiR");
1707 THROWS(IOException.class,
1708 new Fun() {void f() throws Throwable {pb.start();}});
1709 } catch (Throwable t) { unexpected(t);
1710 } finally {
1711 new File("suBdiR/unliKely").delete();
1712 new File("suBdiR").delete();
1713 }
1714 }
1715
1716
1717
1718
1719 try {
1720 new ProcessBuilder("").start();
1721 fail("Expected IOException not thrown");
1722 } catch (IOException e) {
1723 String m = e.getMessage();
1724 if (EnglishUnix.is() &&
1725 ! matches(m, "No such file or directory"))
1726 unexpected(e);
1727 } catch (Throwable t) { unexpected(t); }
1728
1729
1730
1731
1732
1733 for (String programName : new String[] {"\u00f0", "\u01f0"})
1734 try {
1735 new ProcessBuilder(programName).start();
1736 fail("Expected IOException not thrown");
1737 } catch (IOException e) {
1738 String m = e.getMessage();
1739 Pattern p = Pattern.compile(programName);
1740 if (! matches(m, programName)
1741 || (EnglishUnix.is()
1742 && ! matches(m, "No such file or directory")))
1743 unexpected(e);
1744 } catch (Throwable t) { unexpected(t); }
1745
1746
1747
1748
1749 try {
1750 new ProcessBuilder("echo")
1751 .directory(new File("UnLiKeLY"))
1752 .start();
1753 fail("Expected IOException not thrown");
1754 } catch (IOException e) {
1755 String m = e.getMessage();
1756 if (! matches(m, "in directory")
1757 || (EnglishUnix.is() &&
1758 ! matches(m, "No such file or directory")))
1759 unexpected(e);
1760 } catch (Throwable t) { unexpected(t); }
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771 try {
1772 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1773 childArgs.add("print4095");
1774 final int SIZE = 4095;
1775 final Process p = new ProcessBuilder(childArgs).start();
1776 print4095(p.getOutputStream(), (byte) '!');
1777 p.waitFor();
1778 equal(SIZE, p.getInputStream().available());
1779 equal(SIZE, p.getErrorStream().available());
1780 THROWS(IOException.class,
1781 new Fun(){void f() throws IOException {
1782 p.getOutputStream().write((byte) '!');
1783 p.getOutputStream().flush();
1784 }});
1785
1786 final byte[] bytes = new byte[SIZE + 1];
1787 equal(SIZE, p.getInputStream().read(bytes));
1788 for (int i = 0; i < SIZE; i++)
1789 equal((byte) '!', bytes[i]);
1790 equal((byte) 0, bytes[SIZE]);
1791
1792 equal(SIZE, p.getErrorStream().read(bytes));
1793 for (int i = 0; i < SIZE; i++)
1794 equal((byte) 'E', bytes[i]);
1795 equal((byte) 0, bytes[SIZE]);
1796
1797 equal(0, p.getInputStream().available());
1798 equal(0, p.getErrorStream().available());
1799 equal(-1, p.getErrorStream().read());
1800 equal(-1, p.getInputStream().read());
1801
1802 equal(p.exitValue(), 5);
1803
1804 p.getInputStream().close();
1805 p.getErrorStream().close();
1806 p.getOutputStream().close();
1807
1808 InputStream[] streams = { p.getInputStream(), p.getErrorStream() };
1809 for (final InputStream in : streams) {
1810 Fun[] ops = {
1811 new Fun(){void f() throws IOException {
1812 in.read(); }},
1813 new Fun(){void f() throws IOException {
1814 in.read(bytes); }},
1815 new Fun(){void f() throws IOException {
1816 in.available(); }}
1817 };
1818 for (Fun op : ops) {
1819 try {
1820 op.f();
1821 fail();
1822 } catch (IOException expected) {
1823 check(expected.getMessage()
1824 .matches("[Ss]tream [Cc]losed"));
1825 }
1826 }
1827 }
1828 } catch (Throwable t) { unexpected(t); }
1829
1830
1831
1832
1833
1834 try {
1835 final int cases = 4;
1836 for (int i = 0; i < cases; i++) {
1837 final int action = i;
1838 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1839 childArgs.add("sleep");
1840 final byte[] bytes = new byte[10];
1841 final Process p = new ProcessBuilder(childArgs).start();
1842 final CountDownLatch latch = new CountDownLatch(1);
1843 final Thread thread = new Thread() {
1844 public void run() {
1845 try {
1846 latch.countDown();
1847 int r;
1848 switch (action) {
1849 case 0: r = p.getInputStream().read(); break;
1850 case 1: r = p.getErrorStream().read(); break;
1851 case 2: r = p.getInputStream().read(bytes); break;
1852 case 3: r = p.getErrorStream().read(bytes); break;
1853 default: throw new Error();
1854 }
1855 equal(-1, r);
1856 } catch (Throwable t) { unexpected(t); }}};
1857
1858 thread.start();
1859 latch.await();
1860 Thread.sleep(10);
1861 p.destroy();
1862 thread.join();
1863 }
1864 } catch (Throwable t) { unexpected(t); }
1865
1866
1867
1868
1869
1870
1871 try {
1872 if (Unix.is()
1873 && new File("/bin/bash").exists()
1874 && new File("/bin/sleep").exists()) {
1875 final String[] cmd = { "/bin/bash", "-c", "(/bin/sleep 6666)" };
1876 final ProcessBuilder pb = new ProcessBuilder(cmd);
1877 final Process p = pb.start();
1878 final InputStream stdout = p.getInputStream();
1879 final InputStream stderr = p.getErrorStream();
1880 final OutputStream stdin = p.getOutputStream();
1881 final Thread reader = new Thread() {
1882 public void run() {
1883 try { stdout.read(); }
1884 catch (IOException e) {
1885
1886
1887
1888 if (EnglishUnix.is() &&
1889 ! (e.getMessage().matches(".*Bad file.*")))
1890 unexpected(e);
1891 }
1892 catch (Throwable t) { unexpected(t); }}};
1893 reader.setDaemon(true);
1894 reader.start();
1895 Thread.sleep(100);
1896 p.destroy();
1897
1898 check(p.waitFor() != 0);
1899 check(p.exitValue() != 0);
1900 stdout.close();
1901 stderr.close();
1902 stdin.close();
1903
1904
1905
1906
1907 if (Boolean.getBoolean("wakeupJeff!")) {
1908 System.out.println("wakeupJeff!");
1909
1910 new FileInputStream("/bin/sleep").getChannel().close();
1911
1912 String[] wakeupJeff = {
1913 "/bin/bash", "-c",
1914 "/bin/ps --noheaders -Lfp $PPID | " +
1915 "/usr/bin/perl -nale 'print $F[3]' | " +
1916
1917 "/usr/bin/xargs kill -62"
1918 };
1919 new ProcessBuilder(wakeupJeff).start().waitFor();
1920
1921 reader.join();
1922 }
1923 }
1924 } catch (Throwable t) { unexpected(t); }
1925
1926
1927
1928
1929 try {
1930 new File("emptyCommand").delete();
1931 new FileOutputStream("emptyCommand").close();
1932 new File("emptyCommand").setExecutable(false);
1933 new ProcessBuilder("./emptyCommand").start();
1934 fail("Expected IOException not thrown");
1935 } catch (IOException e) {
1936 new File("./emptyCommand").delete();
1937 String m = e.getMessage();
1938 if (EnglishUnix.is() &&
1939 ! matches(m, "Permission denied"))
1940 unexpected(e);
1941 } catch (Throwable t) { unexpected(t); }
1942
1943 new File("emptyCommand").delete();
1944
1945
1946
1947
1948 final Policy policy = new Policy();
1949 Policy.setPolicy(policy);
1950 System.setSecurityManager(new SecurityManager());
1951
1952 try {
1953
1954 policy.setPermissions();
1955 new ProcessBuilder("env").directory(null).directory();
1956 new ProcessBuilder("env").directory(new File("dir")).directory();
1957 new ProcessBuilder("env").command("??").command();
1958 } catch (Throwable t) { unexpected(t); }
1959
1960 THROWS(SecurityException.class,
1961 new Fun() { void f() throws IOException {
1962 policy.setPermissions();
1963 System.getenv("foo");}},
1964 new Fun() { void f() throws IOException {
1965 policy.setPermissions();
1966 System.getenv();}},
1967 new Fun() { void f() throws IOException {
1968 policy.setPermissions();
1969 new ProcessBuilder("echo").start();}},
1970 new Fun() { void f() throws IOException {
1971 policy.setPermissions();
1972 Runtime.getRuntime().exec("echo");}},
1973 new Fun() { void f() throws IOException {
1974 policy.setPermissions(new RuntimePermission("getenv.bar"));
1975 System.getenv("foo");}});
1976
1977 try {
1978 policy.setPermissions(new RuntimePermission("getenv.foo"));
1979 System.getenv("foo");
1980
1981 policy.setPermissions(new RuntimePermission("getenv.*"));
1982 System.getenv("foo");
1983 System.getenv();
1984 new ProcessBuilder().environment();
1985 } catch (Throwable t) { unexpected(t); }
1986
1987
1988 final Permission execPermission
1989 = new FilePermission("<<ALL FILES>>", "execute");
1990
1991 THROWS(SecurityException.class,
1992 new Fun() { void f() throws IOException {
1993
1994 policy.setPermissions(new RuntimePermission("getenv.*"));
1995 ProcessBuilder pb = new ProcessBuilder("env");
1996 pb.environment().put("foo","bar");
1997 pb.start();}},
1998 new Fun() { void f() throws IOException {
1999
2000 policy.setPermissions(execPermission);
2001 ProcessBuilder pb = new ProcessBuilder("env");
2002 pb.environment().put("foo","bar");
2003 pb.start();}});
2004
2005 try {
2006
2007 policy.setPermissions(new RuntimePermission("getenv.*"),
2008 execPermission);
2009 ProcessBuilder pb = new ProcessBuilder("env");
2010 pb.environment().put("foo","bar");
2011 Process p = pb.start();
2012 closeStreams(p);
2013 } catch (IOException e) {
2014 } catch (Throwable t) { unexpected(t); }
2015
2016 try {
2017
2018 policy.setPermissions(execPermission);
2019 Runtime.getRuntime().exec("env", new String[]{});
2020 } catch (IOException e) {
2021 } catch (Throwable t) { unexpected(t); }
2022
2023 try {
2024
2025 policy.setPermissions(execPermission);
2026 new ProcessBuilder("env").start();
2027 } catch (IOException e) {
2028 } catch (Throwable t) { unexpected(t); }
2029
2030
2031 policy.setPermissions(new RuntimePermission("setSecurityManager"));
2032 System.setSecurityManager(null);
2033
2034 }
2035
2036 static void closeStreams(Process p) {
2037 try {
2038 p.getOutputStream().close();
2039 p.getInputStream().close();
2040 p.getErrorStream().close();
2041 } catch (Throwable t) { unexpected(t); }
2042 }
2043
2044
2045
2046
2047 private static class Policy extends java.security.Policy {
2048 private Permissions perms;
2049
2050 public void setPermissions(Permission...permissions) {
2051 perms = new Permissions();
2052 for (Permission permission : permissions)
2053 perms.add(permission);
2054 }
2055
2056 public Policy() { setPermissions(); }
2057
2058 public PermissionCollection getPermissions(CodeSource cs) {
2059 return perms;
2060 }
2061
2062 public PermissionCollection getPermissions(ProtectionDomain pd) {
2063 return perms;
2064 }
2065
2066 public boolean implies(ProtectionDomain pd, Permission p) {
2067 return perms.implies(p);
2068 }
2069
2070 public void refresh() {}
2071 }
2072
2073 private static class StreamAccumulator extends Thread {
2074 private final InputStream is;
2075 private final StringBuilder sb = new StringBuilder();
2076 private Throwable throwable = null;
2077
2078 public String result () throws Throwable {
2079 if (throwable != null)
2080 throw throwable;
2081 return sb.toString();
2082 }
2083
2084 StreamAccumulator (InputStream is) {
2085 this.is = is;
2086 }
2087
2088 public void run() {
2089 try {
2090 Reader r = new InputStreamReader(is);
2091 char[] buf = new char[4096];
2092 int n;
2093 while ((n = r.read(buf)) > 0) {
2094 sb.append(buf,0,n);
2095 }
2096 } catch (Throwable t) {
2097 throwable = t;
2098 } finally {
2099 try { is.close(); }
2100 catch (Throwable t) { throwable = t; }
2101 }
2102 }
2103 }
2104
2105 static ProcessResults run(ProcessBuilder pb) {
2106 try {
2107 return run(pb.start());
2108 } catch (Throwable t) { unexpected(t); return null; }
2109 }
2110
2111 private static ProcessResults run(Process p) {
2112 Throwable throwable = null;
2113 int exitValue = -1;
2114 String out = "";
2115 String err = "";
2116
2117 StreamAccumulator outAccumulator =
2118 new StreamAccumulator(p.getInputStream());
2119 StreamAccumulator errAccumulator =
2120 new StreamAccumulator(p.getErrorStream());
2121
2122 try {
2123 outAccumulator.start();
2124 errAccumulator.start();
2125
2126 exitValue = p.waitFor();
2127
2128 outAccumulator.join();
2129 errAccumulator.join();
2130
2131 out = outAccumulator.result();
2132 err = errAccumulator.result();
2133 } catch (Throwable t) {
2134 throwable = t;
2135 }
2136
2137 return new ProcessResults(out, err, exitValue, throwable);
2138 }
2139
2140
2141
2142
2143 private static class ProcessResults {
2144 private final String out;
2145 private final String err;
2146 private final int exitValue;
2147 private final Throwable throwable;
2148
2149 public ProcessResults(String out,
2150 String err,
2151 int exitValue,
2152 Throwable throwable) {
2153 this.out = out;
2154 this.err = err;
2155 this.exitValue = exitValue;
2156 this.throwable = throwable;
2157 }
2158
2159 public String out() { return out; }
2160 public String err() { return err; }
2161 public int exitValue() { return exitValue; }
2162 public Throwable throwable() { return throwable; }
2163
2164 public String toString() {
2165 StringBuilder sb = new StringBuilder();
2166 sb.append("<STDOUT>\n" + out() + "</STDOUT>\n")
2167 .append("<STDERR>\n" + err() + "</STDERR>\n")
2168 .append("exitValue = " + exitValue + "\n");
2169 if (throwable != null)
2170 sb.append(throwable.getStackTrace());
2171 return sb.toString();
2172 }
2173 }
2174
2175
2176 static volatile int passed = 0, failed = 0;
2177 static void pass() {passed++;}
2178 static void fail() {failed++; Thread.dumpStack();}
2179 static void fail(String msg) {System.out.println(msg); fail();}
2180 static void unexpected(Throwable t) {failed++; t.printStackTrace();}
2181 static void check(boolean cond) {if (cond) pass(); else fail();}
2182 static void check(boolean cond, String m) {if (cond) pass(); else fail(m);}
2183 static void equal(Object x, Object y) {
2184 if (x == null ? y == null : x.equals(y)) pass();
2185 else fail(x + " not equal to " + y);}
2186
2187 public static void main(String[] args) throws Throwable {
2188 try {realMain(args);} catch (Throwable t) {unexpected(t);}
2189 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
2190 if (failed > 0) throw new AssertionError("Some tests failed");}
2191 private static abstract class Fun {abstract void f() throws Throwable;}
2192 static void THROWS(Class<? extends Throwable> k, Fun... fs) {
2193 for (Fun f : fs)
2194 try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
2195 catch (Throwable t) {
2196 if (k.isAssignableFrom(t.getClass())) pass();
2197 else unexpected(t);}}
2198 }